﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Msdn5.Framework
{
    /// <summary>
    /// Json 正反序列化
    /// </summary>
    public static class JsonHelper
    {
        #region Json 正反序列化
        /// <summary>
        /// 转JSON字符串后再转回该对象,完成深拷贝该对象
        /// 转换失败时返回Null
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">任意对象</param>
        /// <returns>该对象的复制体</returns>
        public static T Clone<T>(this T obj)
        {
            return obj.ToJson().JsonTo<T>();
        }
        /// <summary>
        /// 对象转Json
        /// 默认为None不格式化输出内容;Indented为格式化输出内容
        /// </summary>
        /// <param name="obj">任意对象</param> 
        /// <param name="formatting">默认为None,不格式化;Indented为格式化</param>
        /// <returns>Json格式的字符串</returns>
        public static string ToJson(this object obj, Newtonsoft.Json.Formatting formatting = Newtonsoft.Json.Formatting.None)
        {
            
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;//忽略循环检测 
            settings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; //为Null的属性不输出 
            settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //修改属性名称的序列化方式，首字母小写
            settings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
            return Newtonsoft.Json.JsonConvert.SerializeObject(obj, formatting, settings).Trim();
        }
        /// <summary>
        /// 读取JSON文件,并转换成指定格式对象
        /// SucceedAction:将在转换成功后调用
        /// ExpCallback:将在失败后调用
        /// 如果填写绝对路径则读取绝对路径文件
        /// 如果填写相对路径则读取运行路径下的DirectoryPath的文件
        /// </summary>
        /// <typeparam name="T">指定格式</typeparam>
        /// <param name="fileName">如果填写绝对路径则读取绝对路径文件,如果填写相对路径则读取运行路径下的DirectoryPath的文件</param>
        /// <param name="SucceedAction">成功后返回的Action</param>
        /// <param name="ExpCallback">转换失败或错误时返回的Action(默认为null)</param>
        /// <param name="DirectoryPath">读取的路径,默认为JsonFile</param>
        public static void LoadItems<T>(this string fileName, Action<T> SucceedAction, Action<Exception> ExpCallback = null, string DirectoryPath = "JsonFile")
        {
            try
            {
                fileName.ReaderFile(json =>
                {
                    var item = json.JsonTo<T>(ExpCallback); //Encoding.UTF8.GetString(json).JsonTo<T>(ExpCallback);
                    SucceedAction?.Invoke(item);
                }, ExpCallback, DirectoryPath);
            }
            catch (Exception ex)
            {
                if (ExpCallback != null)
                {
                    ExpCallback.Invoke(ex);
                }
                else
                {
                    throw ex;
                }
            }
        }
        /// <summary>
        /// 任意对象保存JSON文件
        /// </summary>
        /// <param name="Obj">实体对象</param>
        /// <param name="Name">保存的文件名(带后缀)</param>
        /// <param name="ExpCallback">执行后的回调函数</param>
        ///  /// <param name="DirectoryPath">默认的存放目录</param>
        public static void SaveJsonItems(this object Obj, string Name, Action<Exception> ExpCallback = null, string DirectoryPath = "JsonFile")
        {
            try
            {
                string json = Obj.ToJson();
                if (!string.IsNullOrEmpty(json))
                {
                    json.WriteFile(Name, System.IO.FileMode.Create, DirectoryPath, callback: ExpCallback);
                    return;
                }
                ExpCallback?.Invoke(new Exception($"当前对象转换为JSON字符串失败!"));
            }
            catch (Exception ex)
            {
                if (ExpCallback != null)
                {
                    ExpCallback.Invoke(ex);
                }
                else
                {
                    throw ex;
                }
            }
        }
        /// <summary>
        /// 任意格式对象反序列化,如果异常返回default(T)
        /// </summary>
        /// <typeparam name="T">需要序列化的对象类型</typeparam>
        /// <param name="Json">Json</param> 
        /// <param name="ExpCallback">异常回调</param>
        /// <returns>序列化后的类型</returns>

        public static T JsonTo<T>(this string Json, Action<Exception> ExpCallback = null)
        {
            try
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Json);
            }
            catch (Exception ex)
            {
                if (ExpCallback != null)
                {
                    ExpCallback.Invoke(ex);
                }
                else
                {
                    throw ex;
                }
                return default(T);
            }

        }
        /// <summary>
        /// Json字符串转JObject
        /// </summary>
        /// <param name="json">字符串</param>
        /// <returns>转换后的JObject</returns>
        public static Newtonsoft.Json.Linq.JObject JsonTo(this string json, Action<Exception> ExpCallback = null)
        {
            try
            {
                return Newtonsoft.Json.Linq.JObject.Parse(json);
            }
            catch (Exception ex)
            {
                if (ExpCallback != null)
                {
                    ExpCallback.Invoke(ex);
                    return null;
                }
                else
                {
                    throw ex;
                }
            }
        }
        /// <summary>
        /// Json字符串转JContainer
        /// JsonTo失败,使用这个.
        /// </summary>
        /// <param name="json">字符串</param>
        /// <returns>JContainer</returns>
        public static Newtonsoft.Json.Linq.JContainer JsonToJContainer(this string json)
        {
            try
            {
                return (Newtonsoft.Json.Linq.JContainer)Newtonsoft.Json.JsonConvert.DeserializeObject(json);
            }
            catch
            {
                return null;
            }

        }
        /// <summary>
        /// 获取一个JObject中的数据,转换为T类型(忽略大小写)
        /// </summary>
        /// <typeparam name="T">需要转换的类型</typeparam>
        /// <param name="jObject">JObject</param>
        /// <param name="key">属性字段(忽略大小写)</param>
        /// <returns>转换后的结果</returns>
        public static T GetJsonValue<T>(this Newtonsoft.Json.Linq.JObject jObject, string key)
        {
            try
            {

                JToken jToken;
                //修正为忽略大小写(2022-05-22 00:06:44)
                if (jObject.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out jToken))
                {
                    if (jToken != null)
                    {
                        return jToken.ToObject<T>();
                    }
                }
            }
            catch
            {
                return default(T);
            }
            return default(T);

        }
        /// <summary>
        /// 获取一个JObject中的数据,转换为T类型
        /// </summary>
        /// <typeparam name="T">需要转换的类型</typeparam>
        /// <param name="jObject">JObject</param>
        /// <param name="path">获取的路径信息</param>
        /// <returns>转换后的结果</returns>
        public static T GetJsonTokenValue<T>(this Newtonsoft.Json.Linq.JObject jObject, string path)
        {
            try
            {
                JToken jt = jObject.SelectToken(path);
                if (jt == null)
                {
                    return default(T);
                }
                else
                {
                    return jt.ToObject<T>();
                }
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// 获取一个JObject中的数据,转换为T类型
        /// </summary>
        /// <typeparam name="T">需要转换的类型</typeparam>
        /// <param name="token">token</param>
        /// <param name="path">获取的路径信息</param>
        /// <returns>转换后的结果</returns>
        public static T GetJsonTokenValue<T>(this Newtonsoft.Json.Linq.JToken token, string path)
        {
            try
            {
                JToken jt = token.SelectToken(path);
                if (jt == null)
                {
                    return default(T);
                }
                else
                {
                    return jt.ToObject<T>();
                }
            }
            catch
            {
                return default(T);
            }
        }
        #endregion
    }
}
